require "uri"

require 'cgi'
require 'openssl'
require 'base64'
require 'open-uri'

class Link < ActiveRecord::Base
    
    has_many :steps
    has_many :paths, :through => :steps
    
    validates_presence_of :uri, :message => "Uri is required"
    
    Url_Reg_Ex = /^((http|https):\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*(\.[a-z]{2,5})?:(([0-9]{1,5})?\/.*)?$/ix
    validates_format_of :uri, :with => Url_Reg_Ex, :message => "Please enter a valid uri." 
          
    
    ###############################################
    # virtual attribute for the thumbnail uri.
    def thumbnail
        return Link.cache_thumbnail(self.uri)
    end
    
    ###############################################
    # pull down the thumbnail
    def self.cache_thumbnail(uri)

        # get the host from the uri
        host = URI.parse(uri).host
        
        # encode it to a file name
        file_name = host.gsub(/[^a-z]/, '_') + '.jpg'
        
        # build a full path to where the thumbnail would actually exist on disk
        full_path = File.join(RAILS_ROOT, "public", "thumbnails", file_name)

        # see if the file already exists
        file_name = get_thumbnail(host, file_name, full_path) if !File.exists?(full_path)
        
        # return the relative url to the thumbnail
        return '/thumbnails/' + file_name
    end
    
    ####################################
    # Gets the path to an alexa thumbnail for a url
    def self.get_thumbnail host, file_name, full_path

        # our secret info is stored in aws.rb
        access_key_id = Account::AccountConfiguration.config(:aws_access_id)
        secret_id = Account::AccountConfiguration.config(:aws_secret_id)
    
        # set up some params for aws
        timestamp = Time.now.utc.strftime("%Y-%m-%dT%H:%M:%S.000Z")

        # the action is Thumbnail
        action = 'Thumbnail'

        # encode the signature
        signature = Base64.encode64(OpenSSL::HMAC::digest(OpenSSL::Digest::Digest.new('SHA1'), secret_id, action + timestamp)).strip

        # build the aws url        
        url = URI.parse(

        "http://ast.amazonaws.com/?" +
        {
            "AWSAccessKeyId"  => access_key_id,
            "Timestamp"       => timestamp,
            "Signature"       => signature,
            "Action"          => action,
            "Url"             => host,
          }.to_a.collect{|item| item.first + "=" + CGI::escape(item.last.to_s) }.join("&")     # Put key value pairs into http GET format
        )
       
        # request the xml describing the thumbnails we want
        doc = open(url).read

        begin
            # scrape the image url out of the xml
            m = doc.match(/\<aws:thumbnail[^\>]+exists=\"true\"\>(.+?)\<\//i)
        
            # we found an image url
            if m && m[1]

                # unencode the url
                thumb_url = m[1]
                thumb_url.gsub!(/\&amp;/, '&')

                # download the thumbnail
                File.open(full_path, "wb") { |f| f.write open(thumb_url).read }
                
                return file_name
                
            # see if it told us no thumbnail exists
            elsif m && m.match(/exists=\"false\"/)
                puts "No thumbnail for #{host}"
            else
                return "not_available.jpg"
            end    
            
        rescue
          puts "Could not access AWS"
        end
    end
    
    ###############################################
    # validation method called when model is saved
    def validate
       format_uri()      
    end
    
    ###############################################
    # formats and validates a uri
    def format_uri()
        
        begin
            new_uri = self.uri
            if new_uri.nil? || new_uri.length <= 0
                errors.add('Please enter a valid url.')
            else
                parsed_uri = URI.parse(new_uri)
                if parsed_uri.scheme.nil?
                    new_uri = "http://" + new_uri
                    parsed_uri = URI.parse(new_uri)
                end                
                
                if  parsed_uri.class != URI::HTTP && parsed_uri.class != URI::HTTPS && parsed_uri.class != URI::FTP
                    errors.add('Please use a valid url.  i.e. http://www.example.com.  Please be sure to include the "http".')
                else                
                    self.uri = parsed_uri.to_s
                end
            end
        rescue URI::InvalidURIError
            errors.add('The format of the url is not valid.')
        end
             
    end
    
end
